import type { Directive, DirectiveBinding } from 'vue'
import type { Position } from '@/Types/Position'

function getStyle(el: HTMLElement, attr: string) {
  return window.getComputedStyle(el, null).getPropertyValue(attr)
}

const instance: Directive = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    // 获取容器宽高
    const containerId = binding.arg || null
    let containerWidth = window.innerWidth
    let containerHeight = window.innerHeight
    if (containerId) {
      // 设置目标元素基础属性
      el.style.cursor = 'move'
      el.style.position = 'fixed'
      const containerEle: HTMLElement | null = document.getElementById(containerId)
      if (containerEle) {
        let { width, height } = containerEle.getBoundingClientRect()
        containerWidth = width
        containerHeight = height
        if (!['fixed', 'absolute', 'relative'].includes(getStyle(containerEle, 'position'))) {
          containerEle.style.position = 'relative'
        }
        el.style.position = 'absolute'
      }
    } else {
      console.error('需要一个限定拖拽范围的ID')
      return
    }

    // 鼠标在目标元素上按下
    el.addEventListener('mousedown', (e) => {
      let { width, height } = el.getBoundingClientRect()
      // 当前目标元素的left与top
      const left = el.offsetLeft
      const top = el.offsetTop
      // 保存按下的鼠标的X与Y
      const mouseX = e.clientX
      const mouseY = e.clientY
      // 计算边界值
      const leftLimit = left
      const rightLimit = containerWidth - left - width
      const topLimit = top
      const bottomLimit = containerHeight - top - height

      // 监听鼠标移动
      document.onmousemove = (e) => {
        // 鼠标移动的距离
        let disX = e.clientX - mouseX
        let disY = e.clientY - mouseY
        // 左右边界
        if (disX < 0 && disX <= -leftLimit) {
          el.style.left = left - leftLimit + 'px'
        } else if (disX > 0 && disX >= rightLimit) {
          el.style.left = left + rightLimit + 'px'
        } else {
          el.style.left = left + disX + 'px'
        }
        // 上下边界
        if (disY < 0 && disY <= -topLimit) {
          el.style.top = top - topLimit + 'px'
        } else if (disY > 0 && disY >= bottomLimit) {
          el.style.top = top + bottomLimit + 'px'
        } else {
          el.style.top = top + disY + 'px'
        }
        return false
      }

      // 监听鼠标抬起
      document.onmouseup = () => {
        if (binding.value && typeof binding.value === 'function') {
          const result: Position = {
            left: el.style.left,
            top: el.style.top
          }
          binding.value(result)
        }
        document.onmousemove = null
        document.onmouseup = null
      }
    })
  },
  unmounted(el: HTMLElement) {}
}

export default { name: 'draggable', instance }
